/*
    Priscilla - A library for enocean network access
    Copyright (C) 2012-2013 B. Aigner / R. Wagner

    This program is free software; you can redistribute it and/or 
    modify it under the terms of the GNU General Public License 
    as published by the Free Software Foundation; either version 2 
    of the License, or at your option any later version. 
 
    This program is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details. 
 
    You should have received a copy of the GNU General Public License 
    along with this program; if not, write to the Free Software 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
 
    Linking this library statically or dynamically with other modules is 
    making a combined work based on this library. Thus, the terms and 
    conditions of the GNU General Public License cover the whole 
    combination. 
 
    As a special exception, the copyright holders of this library give you 
    permission to link this library with independent modules to produce an 
    executable, regardless of the license terms of these independent 
    modules, and to copy and distribute the resulting executable under terms 
    of your choice, provided that you also meet, for each linked independent 
    module, the terms and conditions of the license of that module. An 
    independent module is a module which is not derived from or based on 
    this library. If you modify this library, you may extend this exception 
    to your version of the library, but you are not obligated to do so. If 
    you do not wish to do so, delete this exception statement from your 
    version. 
*/

package at.technikum_wien.embsys.aat.PriscillaCore.telegram;

import java.util.List;

import org.apache.log4j.Logger;

import at.technikum_wien.embsys.aat.PriscillaCore.link.EnOceanLinkImpl;

/**
 * Class representation of an Enocean telegram, as it is received by the Thermokon Enocean/IP gateway
 * 
 * This class contains the java representation of the telegram string (received by the IP gateway).
 * Every field is accessible by a string or an integer type. This class calculates the corresponding
 * values if the fields are written (used by sending a telegram)
 * 
 * @author R. Wagner
 * @version 1.0
 * 
 */
public class Telegram {
	
	private static final Logger log = Logger.getLogger(EnOceanLinkImpl.class);

	/**
	 * Type of telegram, possible values
	 * (see Thermokon STC ethernet datasheet):
	 * 0x0B: telegram received
	 * 0x98: time error telegram
	 * 0xAB: read Thermokon address
	 * 0x8B: response for transmitting a telegram to the gateway
	 * 0x6B: sending telegram
	 */
	int telegram_type = 0;
	String xTelegram_type = "";
	/**
	 * ORG field of the telegram
	 */
	int ORG = 0;
	String xORG = "";
	/**
	 * data byte 0
	 */
	int data0 = 0;
	String xData0 = "";
	/**
	 * data byte 1
	 */
	int data1 = 0;
	String xData1 = "";
	/**
	 * data byte 2
	 */
	int data2 = 0;
	String xData2 = "";
	/**
	 * data byte 3
	 */
	int data3 = 0;
	String xData3 = "";
	/**
	 * complete device ID string
	 */
	String deviceID = "";
	/**
	 * ID byte 0
	 */
	int sensorID0 = 0;
	String xSensorID0 = "";
	/**
	 * ID byte 1
	 */
	int sensorID1 = 0;
	String xSensorID1 = "";
	/**
	 * ID byte 2
	 */
	int sensorID2 = 0;
	String xSensorID2 = "";
	/**
	 * ID byte 3
	 */
	int sensorID3 = 0;
	String xSensorID3 = "";
	/**
	 * status byte (contains T21 and NU bit)
	 */
	int status = 0;
	String xStatus = "";
	/**
	 * Channel or checksum byte
	 * If a telegram should be sent, this byte is the checksum.
	 * If a telegram is received, the function is not clearly defined
	 */
	int channel = 0;
	String xChannel = "";
	/**
	 * TYPE field
	 */
	int type = 0;
	String xType = "";
	/**
	 * FUNC field
	 */
	int func = 0;
	String xFunc = "";

	/**
	 * Manufacturer ID, could be extracted from a teach-in telegram
	 */
	String xManufacturerID = " ";
	int manufacturerID = 0;

	/**
	 * T21 bit from the status byte
	 */
	boolean T21 = false;
	/**
	 * NU bit from the status byte 
	 */
	boolean NU = false;

	/**
	 * learn bit (data byte 0, bit number 3)
	 */
	boolean LRN = false;

	/**
	 * repeat counter value
	 */
	int RPCounter = 0;

	String EEP = "";

	/**
	 * Ctor with a received string.
	 * 
	 * This given string will be analyzed and the corresponding fields will be set.
	 * 
	 * @param dataString Received string
	 */
	public Telegram(String dataString) {
		super();

		System.out.println("EnOcean Raw Data: " + dataString);
		
		xTelegram_type = dataString.substring(4, 6);	//Telegram type: normal/response/sending
		telegram_type = toInt(xTelegram_type);
		xORG = dataString.substring(6, 8);				//ORG byte
		ORG = toInt(xORG);
		xData3 = dataString.substring(8, 10);			//data byte 3 (DB3)
		data3 = toInt(xData3);
		xData2 = dataString.substring(10, 12);			//data byte 2 (DB2)
		data2 = toInt(xData2);
		xData1 = dataString.substring(12, 14);			//data byte 1 (DB1)
		data1 = toInt(xData1);
		xData0 = dataString.substring(14, 16);			//data byte 0 (DB0)
		data0 = toInt(xData0);
		xSensorID3 = dataString.substring(16, 18);		//id byte 3 (ID3)
		sensorID3 = toInt(xSensorID3);
		xSensorID2 = dataString.substring(18, 20);		//id byte 2 (ID2)
		sensorID2 = toInt(xSensorID2);
		xSensorID1 = dataString.substring(20, 22);		//id byte 1 (ID1)
		sensorID1 = toInt(xSensorID1);
		xSensorID0 = dataString.substring(22, 24);		//id byte 0 (ID0)
		sensorID0 = toInt(xSensorID0);
		deviceID = dataString.substring(16, 24);		//whole device ID
		xStatus = dataString.substring(24, 26);			//status byte
		status = toInt(xStatus);
		xChannel = dataString.substring(26, 28);		//channel/checksum byte
		channel = toInt(xChannel);
		
		analyzeTelegram();								//call the analyzing method
	}
	
	/**
	 * Ctor with a received string.
	 * 
	 * This given string will be analyzed and the corresponding fields will be set.
	 * 
	 * @param dataString Received string
	 */
	public Telegram(TelegramESP3 data) {
		super();

		xTelegram_type = "00";
		telegram_type = toInt(xTelegram_type);
		xORG = data.getDataString().substring(0, 2);				//ORG byte
		ORG = toInt(xORG);
		
		//EEP 2.1 ORG
		//to be compatible with future devices, the new ORG numbers are changed to the old ones
		//(from EEP 2.1 to EEP2.0)
		if (this.getxORG().equals("F6")) {
			this.setxORG("05");
		}
		if (this.getxORG().equals("D5")) {
			this.setxORG("06");
		}
		if (this.getxORG().equals("A5")) {
			this.setxORG("07");
		}
		
		if(this.getxORG().equals("00")) { //baseID response
			xData3 = data.getDataString().substring(2, 4);	//data byte 3 (DB3) -> ID3
			data3 = toInt(xData3);
			xData2 = data.getDataString().substring(4, 6);	//data byte 2 (DB2) -> ID2
			data2 = toInt(xData2);
			xData1 = data.getDataString().substring(6, 8);	//data byte 1 (DB1) -> ID1
			data1 = toInt(xData1);
			xData0 = data.getDataString().substring(8, 10);	//data byte 0 (DB0) -> ID0
			data0 = toInt(xData0);
			return;
		}
		
		switch(data.getDataLength()) {
			case 7:
				xData3 = data.getDataString().substring(2, 4);	//data byte 3 (DB3)
				data3 = toInt(xData3);
				xData2 = "00";									//data byte 2 (DB2)
				data2 = toInt(xData2);
				xData1 = "00";									//data byte 1 (DB1)
				data1 = toInt(xData1);
				xData0 = data.getDataString().substring(2, 4);	//data byte 0 (equal to DB0 due to compatibility)
				data0 = toInt(xData0);
				
				xSensorID3 = data.getDataString().substring(4, 6);		//id byte 3 (ID3)
				sensorID3 = toInt(xSensorID3);
				xSensorID2 = data.getDataString().substring(6, 8);		//id byte 2 (ID2)
				sensorID2 = toInt(xSensorID2);
				xSensorID1 = data.getDataString().substring(8, 10);		//id byte 1 (ID1)
				sensorID1 = toInt(xSensorID1);
				xSensorID0 = data.getDataString().substring(10, 12);		//id byte 0 (ID0)
				sensorID0 = toInt(xSensorID0);
				deviceID = data.getDataString().substring(4, 12);		//whole device ID
				
				xStatus = data.getDataString().substring(12, 14);			//status byte
				status = toInt(xStatus);
				break;
				
			case 10:
				xData3 = data.getDataString().substring(2, 4);	//data byte 3 (DB3)
				data3 = toInt(xData3);
				xData2 = data.getDataString().substring(4, 6);	//data byte 2 (DB2)
				data2 = toInt(xData2);
				xData1 = data.getDataString().substring(6, 8);	//data byte 1 (DB1)
				data1 = toInt(xData1);
				xData0 = data.getDataString().substring(8, 10);	//data byte 0 (DB0)
				data0 = toInt(xData0);
				
				xSensorID3 = data.getDataString().substring(10, 12);	//id byte 3 (ID3)
				sensorID3 = toInt(xSensorID3);
				xSensorID2 = data.getDataString().substring(12, 14);	//id byte 2 (ID2)
				sensorID2 = toInt(xSensorID2);
				xSensorID1 = data.getDataString().substring(14, 16);	//id byte 1 (ID1)
				sensorID1 = toInt(xSensorID1);
				xSensorID0 = data.getDataString().substring(16, 18);	//id byte 0 (ID0)
				sensorID0 = toInt(xSensorID0);
				deviceID = data.getDataString().substring(10, 18);		//whole device ID
				
				break;
				
			default:
				return;
			
		}
		
		analyzeTelegram();								//call the analyzing method
	}

	/**
	 * Empty ctor, for creating a new telegram which will be sent
	 */
	public Telegram() {
		super();
	}

	/**
	 * Analyzing this telegram by checking some bits.
	 * 
	 * The telegram will be differed by the different types (RPS, 1BS and 4BS
	 * telegram, see enocean document). The RPS telegram type has different bits
	 * to be checked (T21, NU), the TYPE field is 1 or 2 and the FUNC is not important.
	 * The 1BS telegram has no bits to be checked and the FUNC and TYPE are fixed.
	 * The 8BS telegram will be checked for a teach-in telegram.
	 */
	void analyzeTelegram() {

		// RPS TELEGRAM
		if (xORG.equals("05")) {
			// check T21 bit
			if (checkBit(status, 5) == false) {
				type = 1;
				xType = "01";
				T21 = false;
			} else {
				type = 2;
				xType = "02";
				T21 = true;
			}
			func = 0;
			xFunc = "XX";
			//check NU bit
			if (checkBit(status, 4) == false) {
				NU = false;
			} else {
				NU = true;
			}
			//System.out.println("type: " + type + "    T21: " + T21 + "    NU: " + NU);
			RPCounter = ((byte) status & 0x0F);
			EEP = xORG + "-" + xFunc + "-" + xType;

		// 1BS TELEGRAM
		} else if (xORG.equals("06")) {
			func = 0;
			xFunc = "00";
			type = 1;
			xType = "01";
			EEP = xORG + "-" + xFunc + "-" + xType;
			RPCounter = ((byte) status & 0x0F);

		// 4BS TELEGRAM
		} else if (xORG.equals("07")) {
			// check LearnButton
			if (checkBit(data0, 3) == false) {
				LRN = true;
				func = (((byte) data3) & 0xFC) >> 2;
				type = (((byte) data3 & 0x03) << 5) + (((byte) data2 & 0xF8) >> 3);
				manufacturerID = ((byte) data1 & 0xFF) + (((byte) data2 & 0x07) << 8);
			} else {
				LRN = false;
				func = 0;
				type = 0;
			}
			RPCounter = ((byte) status & 0x0F);

		}

	}

	/**
	 * Print method to print out a decoded telegram
	 */
	public void printTelegram() {

		log.debug("Telegram Print    DeviceID: " + deviceID + ", func: " + func + ", type: " + type + ", data0: " + data0 + ", data1: "
				+ data1 + ", data2: " + data2 + ", data3: " + data3);

	}

	/**
	 * Parse an ASCII string to an Integer
	 * 
	 * @param ascii
	 * @return HEX interpretation of the ASCII string
	 */
	int toInt(String ascii) {
		return Integer.parseInt(ascii, 16);
	}

	/**
	 * This method returns the TYPE of given device ID, it is searched within the given list
	 * 
	 * This methods walks through the given list and searches for the device ID,
	 * if it is found, the TYPE will be returned, if not 0x00 will be returned.
	 * 
	 * @param deviceID Device ID string
	 * @param list The actual known devices
	 * @return TYPE of the given deviceID, 0x00 if the device is not known
	 */
	int getDeviceTypeFromID(String deviceID, List<Device> list) {

		int type = 0x00;
		int ID0 = toInt(deviceID.substring(6, 8)); //split out ID0
		int ID1 = toInt(deviceID.substring(4, 6)); //split out ID1
		int ID2 = toInt(deviceID.substring(2, 4)); //split out ID2
		int ID3 = toInt(deviceID.substring(0, 2)); //split out ID3

		//iterate list
		for (int i = 0; i < list.size(); i++) {
			if (ID0 == list.get(i).id0) {
				if (ID1 == list.get(i).id1) {
					if (ID2 == list.get(i).id2) {
						if (ID3 == list.get(i).id3) {
							type = list.get(i).type; //save the type
							break;
						}
					}
				}
			}
		}

		return type; //return TYPE value
	}

	/**
	 * The method checks, if a bit is set in the given value
	 * 
	 * @param value
	 * @param bitNr
	 * @return true if the bit is set, false otherwise
	 */
	boolean checkBit(int value, int bitNr) {
		return (value & (1 << bitNr)) != 0;
	}

	/**
	 * Set a bit in the given value
	 * 
	 * @param value
	 * @param bitNr
	 * @return The old value + the new set bit
	 */
	int setBit(int value, int bitNr) {
		return value | (1 << bitNr);
	}

	/**
	 * Clear a bit in the given value
	 * 
	 * @param value
	 * @param bitNr
	 * @return The old value + the new cleared bit
	 */
	int clrBit(int value, int bitNr) {
		return value & (~(1 << bitNr));
	}

	// GETTERS
	/**
	 * @return String representation of the telegram (used for sending it over IP)
	 */
	public String getIPTelegramString() {
		return "A55A" + this.getxTelegram_type() + this.getxORG() + this.getxData3() + this.getxData2() + this.getxData1() + this.getxData0()
				 + this.getxSensorID3() + this.getxSensorID2() + this.getxSensorID1() + this.getxSensorID0() + this.getxStatus() + this.calcChecksum();
	}
	
	/**
	 * @return String representation of the telegram (used for sending it over serial)
	 */
	public String getESP3TelegramString() {
		return new TelegramESP3(this).getDataString();
	}
	/**
	 * @return RawData representation of the telegram (used for sending it over serial)
	 */

	/**
	 * @return Size of ESP3 telegram
	 */
	public int getESP3TelegramSize() {
		return new TelegramESP3(this).getSize();
	}
	
	/**
	 * Get the device ID of this telegram
	 * 
	 * @return Full device ID
	 */
	public String getDeviceID() {
		return this.deviceID;
	}

	/**
	 * Get device ID byte 0
	 * @return Integer byte of device ID 0
	 */
	public int getSensorID0() {
		return sensorID0;
	}

	/**
	 * Get device ID byte 1
	 * @return Integer byte of device ID 1
	 */
	public int getSensorID1() {
		return sensorID1;
	}

	/**
	 * Get device ID byte 2
	 * @return Integer byte of device ID 2
	 */
	public int getSensorID2() {
		return sensorID2;
	}

	/**
	 * Get device ID byte 3
	 * @return Integer byte of device ID 3
	 */
	public int getSensorID3() {
		return sensorID3;
	}

	/**
	 * Get ORG byte
	 * @return Integer byte of ORG number
	 */
	public int getORG() {
		return ORG;
	}

	/**
	 * Get data byte 0
	 * @return Integer byte of data byte 0
	 */
	public int getData0() {
		return data0;
	}

	/**
	 * Get data byte 1
	 * @return Integer byte of data byte 1
	 */
	public int getData1() {
		return data1;
	}

	/**
	 * Get data byte 2
	 * @return Integer byte of data byte 2
	 */
	public int getData2() {
		return data2;
	}

	/**
	 * Get data byte 3
	 * @return Integer byte of data byte 3
	 */
	public int getData3() {
		return data3;
	}

	/**
	 * Get status byte
	 * @return Integer byte of status
	 */
	public int getStatus() {
		return status;
	}

	/**
	 * Get channel/checksum byte
	 * @return Integer byte of channel/checksum byte
	 */
	public int getChannel() {
		return channel;
	}

	/**
	 * Get string of ORG
	 * @return String of ORG
	 */
	public String getxORG() {
		return xORG;
	}
	
	/**
	 * Get string of data byte 0
	 * @return String of data byte 0
	 */
	public String getxData0() {
		return xData0;
	}

	/**
	 * Get string of data byte 1
	 * @return String of data byte 1
	 */
	public String getxData1() {
		return xData1;
	}

	/**
	 * Get string of data byte 2
	 * @return String of data byte 2
	 */
	public String getxData2() {
		return xData2;
	}

	/**
	 * Get string of data byte 3
	 * @return String of data byte 3
	 */
	public String getxData3() {
		return xData3;
	}

	/**
	 * Get string of device ID byte 0
	 * @return String of device ID byte 0
	 */
	public String getxSensorID0() {
		return xSensorID0;
	}

	/**
	 * Get string of device ID byte 1
	 * @return String of device ID byte 1
	 */
	public String getxSensorID1() {
		return xSensorID1;
	}

	/**
	 * Get string of device ID byte 2
	 * @return String of device ID byte 2
	 */
	public String getxSensorID2() {
		return xSensorID2;
	}

	/**
	 * Get string of device ID byte 3
	 * @return String of device ID byte 3
	 */
	public String getxSensorID3() {
		return xSensorID3;
	}

	/**
	 * Get string of status byte
	 * @return String of status byte
	 */
	public String getxStatus() {
		return xStatus;
	}

	/**
	 * Get string of channel/checksum
	 * @return String of channel/checksum
	 */
	public String getxChannel() {
		return xChannel;
	}

	/**
	 * Get type byte
	 * @return Integer of type byte
	 */
	public int getType() {
		return type;
	}

	/**
	 * Get string of type byte
	 * @return String of type byte
	 */
	public String getxType() {
		return xType;
	}

	/**
	 * Get func byte
	 * @return Integer of func byte
	 */
	public int getFunc() {
		return func;
	}

	/**
	 * Get string of func byte
	 * @return String of func byte
	 */
	public String getxFunc() {
		return xFunc;
	}

	/**
	 * Get string of manufacturer ID
	 * @return String of manufacturer ID
	 */
	public String getxManufacturerID() {
		return xManufacturerID;
	}

	/**
	 * Get integer representation of manufacturer ID
	 * @return Integer of representation of manufacturer ID
	 */
	public int getManufacturerID() {
		return manufacturerID;
	}

	/**
	 * Get T21 bit
	 * @return T21 bit
	 */
	public boolean getT21() {
		return T21;
	}

	/**
	 * Get NU bit
	 * @return NU bit
	 */
	public boolean getNU() {
		return NU;
	}

	/**
	 * Get learn bit
	 * @return Learn bit
	 */
	public boolean getLRN() {
		return LRN;
	}

	/**
	 * Get repeat counter value
	 * @return Repeat counter value
	 */
	public int getRPCounter() {
		return RPCounter;
	}

	/**
	 * Get string representation of EEP
	 * @return EEP (Enocean equipment profile), string representation (e.g. 07_10_01)
	 */
	public String getEEP() {
		return EEP;
	}

	
	/**
	 * Set type field
	 */
	public void setType(int type) {
		this.type = type;
		this.xType = Integer.toHexString(type);
		if(this.type <= 0x0F) this.xType = "0" + this.xType;
	}

	/**
	 * Set type field
	 */
	public void setxType(String xType) {
		this.xType = xType;
		this.type = Integer.parseInt(xType, 16);
		if(this.xType.length() < 2) this.xType = "0" + this.xType;
	}

	/**
	 * Set func field
	 */
	public void setFunc(int func) {
		this.func = func;
		this.xFunc = Integer.toHexString(func);
		if(this.func <= 0x0F) this.xFunc = "0" + this.xFunc;
	}

	/**
	 * Set func field
	 */
	public void setxFunc(String xFunc) {
		this.xFunc = xFunc;
		this.func = Integer.parseInt(xFunc, 16);
		if(this.xFunc.length() < 2) this.xFunc = "0" + this.xFunc;
	}

	/**
	 * Set ORG field
	 */
	public void setORG(int oRG) {
		this.ORG = oRG;
		this.xORG = Integer.toHexString(oRG);
		if(this.ORG <= 0x0F) this.xORG = "0" + this.xORG;
	}
	/**
	 * Set ORG field
	 */
	public void setxORG(String xORG) {
		this.xORG = xORG;
		this.ORG = Integer.parseInt(xORG, 16);
		if(this.xORG.length() < 2) this.xORG = "0" + this.xORG;
	}
	
	/**
	 * Set data byte 0 field
	 */
	public void setData0(int data0) {
		this.data0 = data0;
		this.xData0 = Integer.toHexString(data0);
		if(this.data0 <= 0x0F) this.xData0 = "0" + this.xData0;
	}

	/**
	 * Set data byte 0 field
	 */
	public void setxData0(String xData0) {
		this.xData0 = xData0;
		this.data0 = Integer.parseInt(xData0, 16);
		if(this.xData0.length() < 2) this.xData0 = "0" + this.xData0;
	}

	/**
	 * Set data byte 1 field
	 */
	public void setData1(int data1) {
		this.data1 = data1;
		this.xData1 = Integer.toHexString(data1);
		if(this.data1 <= 0x0F) this.xData1 = "0" + this.xData1;
	}

	/**
	 * Set data byte 1 field
	 */
	public void setxData1(String xData1) {
		this.xData1 = xData1;
		this.data1 = Integer.parseInt(xData1, 16);
		if(this.xData1.length() < 2) this.xData1 = "0" + this.xData1;
	}

	/**
	 * Set data byte 2 field
	 */
	public void setData2(int data2) {
		this.data2 = data2;
		this.xData2 = Integer.toHexString(data2);
		if(this.data2 <= 0x0F) this.xData2 = "0" + this.xData2;
	}

	/**
	 * Set data byte 2 field
	 */
	public void setxData2(String xData2) {
		this.xData2 = xData2;
		this.data2 = Integer.parseInt(xData2, 16);
		if(this.xData2.length() < 2) this.xData2 = "0" + this.xData2;
	}

	/**
	 * Set data byte 3 field
	 */
	public void setData3(int data3) {
		this.data3 = data3;
		this.xData3 = Integer.toHexString(data3);
		if(this.data3 <= 0x0F) this.xData3 = "0" + this.xData3;
	}

	/**
	 * Set data byte 3 field
	 */
	public void setxData3(String xData3) {
		this.xData3 = xData3;
		this.data3 = Integer.parseInt(xData3, 16);
		if(this.xData3.length() < 2) this.xData3 = "0" + this.xData3;
	}

	/**
	 * Set whole device ID field
	 */
	public void setDeviceID(String deviceID) {
		
		if(deviceID.length() < 8) {
			for(int i = deviceID.length(); i<8; i++) {
				deviceID = "0" + deviceID;
			}
		}
		
		this.setxSensorID3(deviceID.substring(0, 2));
		
		this.setxSensorID2(deviceID.substring(2, 4));
		
		this.setxSensorID1(deviceID.substring(4, 6));
		
		this.setxSensorID0(deviceID.substring(6, 8));
		

		this.deviceID = this.getxSensorID3() + this.getxSensorID2() +this.getxSensorID1() +this.getxSensorID0() ;
	}

	/**
	 * Set device ID 0 field
	 */
	public void setSensorID0(int sensorID0) {
		this.sensorID0 = sensorID0;
		this.xSensorID0 = Integer.toHexString(sensorID0);
		if(this.sensorID0 <= 0x0F) this.xSensorID0 = "0" + this.xSensorID0;
	}

	/**
	 * Set device ID 0 field
	 */
	public void setxSensorID0(String xSensorID0) {
		this.xSensorID0 = xSensorID0;
		this.sensorID0 = Integer.parseInt(xSensorID0, 16);
		if(this.xSensorID0.length() < 2) this.xSensorID0 = "0" + this.xSensorID0;
	}

	/**
	 * Set device ID 1 field
	 */
	public void setSensorID1(int sensorID1) {
		this.sensorID1 = sensorID1;
		this.xSensorID1 = Integer.toHexString(sensorID1);
		if(this.sensorID1 <= 0x0F) this.xSensorID1 = "0" + this.xSensorID1;
	}

	/**
	 * Set device ID 1 field
	 */
	public void setxSensorID1(String xSensorID1) {
		this.xSensorID1 = xSensorID1;
		this.sensorID1 = Integer.parseInt(xSensorID1, 16);
		if(this.xSensorID1.length() < 2) this.xSensorID1 = "0" + this.xSensorID1;
	}

	/**
	 * Set device ID 2 field
	 */
	public void setSensorID2(int sensorID2) {
		this.sensorID2 = sensorID2;
		this.xSensorID2 = Integer.toHexString(sensorID2);
		if(this.sensorID2 <= 0x0F) this.xSensorID2 = "0" + this.xSensorID2;
	}

	/**
	 * Set device ID 2 field
	 */
	public void setxSensorID2(String xSensorID2) {
		this.xSensorID2 = xSensorID2;
		this.sensorID2 = Integer.parseInt(xSensorID2, 16);
		if(this.xSensorID2.length() < 2) this.xSensorID2 = "0" + this.xSensorID2;
	}

	/**
	 * Set device ID 3 field
	 */
	public void setSensorID3(int sensorID3) {
		this.sensorID3 = sensorID3;
		this.xSensorID3 = Integer.toHexString(sensorID3);
		if(this.sensorID3 <= 0x0F) this.xSensorID3 = "0" + this.xSensorID3;
	}

	/**
	 * Set device ID 3 field
	 */
	public void setxSensorID3(String xSensorID3) {
		this.xSensorID3 = xSensorID3;
		this.sensorID3 = Integer.parseInt(xSensorID3, 16);
		if(this.xSensorID3.length() < 2) this.xSensorID3 = "0" + this.xSensorID3;
	}
	
	/**
	 * Set status field
	 */
	public void setStatus(int status) {
		this.status = status;
		this.xStatus = Integer.toHexString(status);
		if(this.status <= 0x0F) this.xStatus = "0" + this.xStatus;
		//check NU bit and set the member
		if (checkBit(this.status, 4) == false) {
			NU = false;
		} else {
			NU = true;
		}
		//check T21 bit and set the member
		if (checkBit(this.status, 5) == false) {
			type = 1;
			xType = "01";
			T21 = false;
		} else {
			type = 2;
			xType = "02";
			T21 = true;
		}
	}

	/**
	 * Set status field
	 */
	public void setxStatus(String xStatus) {
		this.xStatus = xStatus;
		this.status = Integer.parseInt(xStatus, 16);
		if(this.xStatus.length() < 2) this.xStatus = "0" + this.xStatus;
		//check NU bit and set the member
		if (checkBit(this.status, 4) == false) {
			NU = false;
		} else {
			NU = true;
		}
		//check T21 bit and set the member
		if (checkBit(this.status, 5) == false) {
			type = 1;
			xType = "01";
			T21 = false;
		} else {
			type = 2;
			xType = "02";
			T21 = true;
		}
	}

	/**
	 * Set channel field
	 */
	public void setChannel(int channel) {
		this.channel = channel;
		this.xChannel = Integer.toHexString(channel);
		if(this.channel <= 0x0F) this.xChannel = "0" + this.xChannel;
	}

	/**
	 * Set channel field
	 */
	public void setxChannel(String xChannel) {
		this.xChannel = xChannel;
		this.channel = Integer.parseInt(xChannel, 16);
		if(this.xChannel.length() < 2) this.xChannel = "0" + this.xChannel;
	}

	/**
	 * Set manufacturer ID field
	 */
	public void setxManufacturerID(String xManufacturerID) {
		this.xManufacturerID = xManufacturerID;
		this.manufacturerID = Integer.parseInt(xManufacturerID, 16);
		if(this.xManufacturerID.length() < 2) this.xManufacturerID = "0" + this.xManufacturerID;
	}

	/**
	 * Set manufacturer ID field
	 */
	public void setManufacturerID(int manufacturerID) {
		this.manufacturerID = manufacturerID;
		this.xManufacturerID = Integer.toHexString(manufacturerID);
		if(this.manufacturerID <= 0x0F) this.xManufacturerID = "0" + this.xManufacturerID;
	}

	/**
	 * Set T21 bit field
	 */
	public void setT21(boolean t21) {
		T21 = t21;
	}

	/**
	 * Set NU bit field
	 */
	public void setNU(boolean nU) {
		NU = nU;
	}

	/**
	 * Set learn bit field
	 */
	public void setLRN(boolean lRN) {
		LRN = lRN;
	}

	/**
	 * Set repeat counter field
	 */
	public void setRPCounter(int rPCounter) {
		RPCounter = rPCounter;
	}

	/**
	 * Set EEP string field
	 */
	public void setEEP(String eEP) {
		EEP = eEP;
	}
	
	
	/**
	 * Calculate checksum for Enocean frames
	 * 
	 * The checksum in Enocean telegrams is the sum over all databytes
	 * (except SYNC bytes A55A and the checksum itself), the sum 
	 * will be truncated to the low byte
	 * 
	 * @return 2 ASCII symbols with the calculated checksum
	 */
	private String calcChecksum() {
		int sum = 0;
		String ret;
		sum += this.getTelegram_type();
		sum += this.getORG();
		sum += this.getData3();
		sum += this.getData2();
		sum += this.getData1();
		sum += this.getData0();
		sum += this.getSensorID3();
		sum += this.getSensorID2();
		sum += this.getSensorID1();
		sum += this.getSensorID0();
		sum += this.getStatus();
		
		ret = Integer.toHexString(sum & 0xFF);
		//check for 1 digit and append a trailing zero
		if((sum & 0xFF) <= 0x0F) {
			ret = "0" + ret;
		}
		return ret;
	}

	
	/**
	 * Get the telegram type
	 * @return Telegram type
	 */
	public int getTelegram_type() {
		return telegram_type;
	}

	/**
	 * Set telegram type
	 * 
	 * @param telegram_type
	 * Type of telegram, possible values
	 * (see Thermokon STC ethernet datasheet):
	 * 0x0B: telegram received
	 * 0x98: time error telegram
	 * 0xAB: read Thermokon address
	 * 0x8B: response for transmitting a telegram to the gateway
	 * 0x6B: sending telegram
	 */
	public void setTelegram_type(int telegram_type) {
		this.telegram_type = telegram_type;
		this.xTelegram_type = Integer.toHexString(telegram_type);
		if(this.telegram_type <= 0x0F) this.xTelegram_type = "0" + this.xTelegram_type;
	}

	/**
	 * Get telegram type
	 */
	public String getxTelegram_type() {
		return xTelegram_type;
	}

	/**
	 * Set telegram type field
	 */
	public void setXtelegram_type(String xtelegram_type) {
		this.xTelegram_type = xtelegram_type;
		this.telegram_type = Integer.parseInt(xtelegram_type, 16);
		if(this.xTelegram_type.length() < 2) this.xTelegram_type = "0" + this.xTelegram_type;
	}

}
